﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FrameworkX.ObjectSpace.Data.Providers;
using System.Reflection;

namespace FrameworkX.ObjectSpace.Data.Schema
{
    public static class ConstraintHelper 
    {
        public static bool GeneratePrimaryKey(Providers.IDatabaseProvider provider, Type typeAppliedOn, System.Reflection.PropertyInfo pinfo, StringBuilder sbBeforeTable, StringBuilder sbField, StringBuilder sbAfterTable, StringBuilder sbPostGeneration)
        {
            PrimaryKeyAttribute pk = Util.CommonHelper.GetAttribute<PrimaryKeyAttribute>(pinfo);
            if (pk != null)
            {
                if (sbAfterTable.Length > 0)
                {
                    sbAfterTable.Append(",\n");
                }
                ISqlDataTypeTranslator translator = provider.GetDataTypeTranslator();
                sbAfterTable.Append(string.Format("CONSTRAINT {1}PK_{0}{2} PRIMARY KEY CLUSTERED \n(", typeAppliedOn.Name, translator.OpeningIdentifier, translator.ClosingIdentifier));

                string[] fields = pk.Fields;
                List<string> list = new List<string>();

                if (fields == null)
                {
                    list.Add(pinfo.Name);
                }
                else
                {
                    if (fields.Length == 0)
                    {
                        list.Add(pinfo.Name);
                    }
                    else
                    {
                        list.AddRange(fields);
                    }
                }

                foreach (string field in list)
                {
                    sbAfterTable.Append(string.Format("\t{1}{0}{2} ASC ,", field, translator.OpeningIdentifier, translator.ClosingIdentifier));
                }
                sbAfterTable.Remove(sbAfterTable.Length - 1, 1);

                sbAfterTable.Append("\n)");
                return true;
            }
            return false;
        }

        public static bool GenerateForiegnKey(Providers.IDatabaseProvider provider, Type typeAppliedOn, System.Reflection.PropertyInfo pinfo, StringBuilder sbBeforeTable, StringBuilder sbField, StringBuilder sbAfterTable, StringBuilder sbPostGeneration)
        {
            ForiegnKeyAttribute key = Util.CommonHelper.GetAttribute<ForiegnKeyAttribute>(pinfo);
            if (key != null)
            {
                ISqlDataTypeTranslator translator = provider.GetDataTypeTranslator();
                if (sbAfterTable.Length > 0)
                {
                    sbAfterTable.Append(",\n");
                }


                sbAfterTable.Append(string.Format("CONSTRAINT {2}FK_{0}_{1}{3} FOREIGN KEY \n", typeAppliedOn.Name, key.EntityName  , translator.OpeningIdentifier, translator.ClosingIdentifier));

                sbAfterTable.Append(string.Format("({3}{0}{4}) REFERENCES {3}{1}{4} ({3}{2}{4}) ", 
                    pinfo.Name, key.EntityName , key.ForiegnKeyField,  translator.OpeningIdentifier, translator.ClosingIdentifier));

                sbAfterTable.Remove(sbAfterTable.Length - 1, 1);
                return true;
            }
            return false;
        }

        public static bool GenerateUniqueConstraint(IDatabaseProvider provider, Type typeAppliedOn, PropertyInfo pinfo, StringBuilder sbBeforeTable, StringBuilder sbField, StringBuilder sbAfterTable, StringBuilder sbPostGeneration)
        {
            UniqueFieldsConstraintAttribute ufc = Util.CommonHelper.GetAttribute<UniqueFieldsConstraintAttribute>(pinfo);

            if (ufc != null)
            {
                string[] properties = ufc.Properties;
                sbAfterTable.Append("UNIQUE (");
                ISqlDataTypeTranslator translator = provider.GetDataTypeTranslator();
                int i = 0;
                foreach (string propertyName in properties)
                {
                    PropertyInfo pinfoUf = typeAppliedOn.GetProperty(propertyName);
                    string fieldName = propertyName;
                    if (i > 0)
                    {
                        sbAfterTable.Append(",");
                    }
                    sbAfterTable.Append(string.Format("{0}{1}{2}", translator.OpeningIdentifier, fieldName, translator.ClosingIdentifier));
                    i++;
                }
                sbAfterTable.Append(")");
                return true;
            }
            return false;

        }

        public static bool GenerateIndex(Providers.IDatabaseProvider provider, Type typeAppliedOn, System.Reflection.PropertyInfo pinfo, StringBuilder sbBeforeTable, StringBuilder sbField, StringBuilder sbAfterTable, StringBuilder sbPostGeneration)
        {
            IndexAttribute ix = Util.CommonHelper.GetAttribute<IndexAttribute>(typeAppliedOn);

            if (ix != null)
            {

                ISqlDataTypeTranslator translator = provider.GetDataTypeTranslator();
                if (sbPostGeneration.Length > 0)
                {
                    sbPostGeneration.Append("\nGO\n");
                }

                string isUnique = ix.IsUnique ? "UNIQUE" : "";
                string isClustered = ix.IsClustered ? "CLUSTERED" : "NONCLUSTERED";
                
                string[] parameters = ix.Parameters;
                sbPostGeneration.Append(string.Format("CREATE {0} {1} INDEX {4}IX_{2}{5} ON {4}{3}{5}\n(", 
                    isUnique, isClustered, ix.IndexName, typeAppliedOn.Name, translator.OpeningIdentifier, translator.ClosingIdentifier));
                foreach (string parameter in parameters)
                {
                    string order = char.IsUpper(parameter[0]) ? "ASC" : "DESC";
                    string fieldName = parameter;
                    sbPostGeneration.Append(string.Format("{0}{1}{2} {3},", translator.OpeningIdentifier, fieldName, 
                        translator.ClosingIdentifier, order));

                }
                sbPostGeneration.Remove(sbPostGeneration.Length - 1, 1);
                sbPostGeneration.Append(")");
                return true;
            }
            return false;
        }
    }
}
